package com.darkidiot.session;

import com.darkidiot.session.util.IpUtil;
import com.darkidiot.session.util.WebUtil;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.*;
import java.util.List;

/**
 * 装修模式包装HttpServletRequest
 * session attribute持久化到redis
 * Copyright (c) for darkidiot
 * Date:2017/4/14
 * Author: <a href="darkidiot@icloud.com">darkidiot</a>
 * School: CUIT
 * Desc:
 */
@Slf4j
class DistributedHttpServletRequest extends HttpServletRequestWrapper {
    private final HttpServletRequest request;
    private final HttpServletResponse response;
    @Getter
    @Setter
    private String sessionCookieName;
    @Setter
    private String cookieDomain;
    @Getter
    @Setter
    private String cookieContextPath;
    @Getter
    @Setter
    private int maxInactiveInterval;
    @Getter
    @Setter
    private int cookieMaxAge;
    private DistributedSessionManager sessionManager;
    private DistributedSession distributedSession;
    private static final Splitter dotSplitter = Splitter.on('.').omitEmptyStrings().trimResults();

    DistributedHttpServletRequest(HttpServletRequest request, HttpServletResponse response) {
        super(request);
        this.request = request;
        this.response = response;
        this.sessionManager = DistributedSessionManager.getInstance();
    }

    @Override
    public HttpSession getSession(boolean create) {
        return doGetSession(create);
    }

    @Override
    public HttpSession getSession() {
        return doGetSession(true);
    }

    private String getCookieDomain() {
        if (!Strings.isNullOrEmpty(cookieDomain)) {
            return cookieDomain;
        }

        String serverName = request.getServerName();
        if (IpUtil.isIp(serverName)) {
            return serverName;
        }

        //兼容测试环境
        List<String> parts = dotSplitter.splitToList(serverName);
        if (parts.size() > 2) {
            return Joiner.on('.').join(parts.subList(1, parts.size()));
        }
        return serverName;
    }

    DistributedSession currentSession() {
        return distributedSession;
    }

    private HttpSession doGetSession(boolean create) {
        if (distributedSession == null) {
            Cookie cookie = WebUtil.findCookie(this, getSessionCookieName());
            if (cookie != null && !"__DELETED__".equals(cookie.getValue())) {
                String msid = cookie.getValue();
                log.debug("Find session`s id from cookie:[{}]", msid);
                distributedSession = buildDistributedSession(msid, false);
            } else {
                distributedSession = buildDistributedSession(create);
            }
        } else {
            log.debug("Session[{}] was existed.", distributedSession.getId());
        }
        return distributedSession;
    }

    private DistributedSession buildDistributedSession(String msid, boolean createCookie) {
        DistributedSession session = new DistributedSession(sessionManager, request, msid);
        session.setMaxInactiveInterval(maxInactiveInterval);
        if (createCookie) {
            WebUtil.addCookie(this, response, getSessionCookieName(), msid, getCookieDomain(), getCookieContextPath(), cookieMaxAge, true);
        }
        return session;
    }

    private DistributedSession buildDistributedSession(boolean create) {
        if (create) {
            DistributedSession session = buildDistributedSession(sessionManager.getSessionIdGenerator().generateId(request), true);
            log.debug("Build new session[{}].", session.getId());
            return session;
        }
        return distributedSession;
    }
}
